home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 12.3 KB | 498 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: FWTxtBuf.h
- // Release Version: $ 1.0d11 $
- // Modified by MEB to support non-single-byte characters
- //
- // Copyright: © 1993, 1995 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWOS.hpp"
-
- #ifndef FWTXTBUF_H
- #include "FWTxtBuf.h"
- #endif
-
- #ifndef FWMEMORY_H
- #include "FWMemory.h"
- #endif
-
- #if FW_LIB_EXPORT_PRAGMAS
- #pragma lib_export on
- #endif
-
- //========================================================================================
- // RunTime Info
- //========================================================================================
-
- #ifdef FW_BUILD_MAC
- #pragma segment FWGraphx_TextBuf
- #endif
-
- //========================================================================================
- // Static Initialization
- //========================================================================================
-
- #define FW_kStaticBufferSize 256
- #define FW_kDynamicBufferSizeIncrement 256
-
- FW_Byte FW_CPrivTextBuffer::gStaticBuffer[FW_kStaticBufferSize];
- unsigned short FW_CPrivTextBuffer::gStaticBufferUseCount = 0;
-
- //========================================================================================
- // CLASS FW_CPrivTextBuffer
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::FW_CPrivTextBuffer(const FW_CString* string) :
- fString(string),
- fReader(NULL),
- fCurrentLine(NULL),
- fIsDone(FALSE),
- fDynamicBufferBase(NULL)
- {
- gStaticBufferUseCount ++;
-
- GetNextLine();
- FW_END_CONSTRUCTOR
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::FW_CPrivTextBuffer(FW_CTextReader* reader) :
- fString(NULL),
- fReader(reader),
- fCurrentLine(NULL),
- fIsDone(FALSE),
- fDynamicBufferBase(NULL)
- {
- gStaticBufferUseCount ++;
-
- GetNextLine();
- FW_END_CONSTRUCTOR
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::~FW_CPrivTextBuffer
- //----------------------------------------------------------------------------------------
-
- FW_CPrivTextBuffer::~FW_CPrivTextBuffer()
- {
- FW_START_DESTRUCTOR
-
- gStaticBufferUseCount --;
-
- if(fDynamicBufferBase != NULL)
- FW_CMemoryManager::FreeBlock((void*)fDynamicBufferBase);
-
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetTotalLength
- //----------------------------------------------------------------------------------------
-
- FW_ByteCount FW_CPrivTextBuffer::GetTotalLength() const
- {
- // MetroWerks bug workaround [AMB]
- const FW_CString* string = fString;
-
- if (string != NULL)
- return string->GetByteLength();
-
- FW_ASSERT(fReader != NULL);
- return fReader->GetByteLength();
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::IsDone
- //----------------------------------------------------------------------------------------
-
- FW_Boolean FW_CPrivTextBuffer::IsDone() const
- {
- return fIsDone;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetNextLine
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::GetNextLine()
- {
- // the user should not call this method after we told him we're done
- FW_ASSERT(!IsDone());
-
- // MetroWerks bug workaround [AMB]
- const FW_CString* string = fString;
-
- if (string != NULL)
- {
- // we have a string
- if (fCurrentLine == NULL)
- {
- // Strings come as one chunk; therefore, we shouldn't have any on the way in
- fCurrentLine = (FW_Byte*)(const FW_Char*) *string;
- fCurrentLineLength = string->GetByteLength();
- fIsDone = fCurrentLineLength == 0;
- }
- else
- {
- // otherwise, this is the second request, and we're done
- fIsDone = TRUE;
- }
- }
- else
- {
- if (fReader != NULL)
- {
- const FW_Byte* run;
- FW_ByteCount runLen;
- fReader->PeekRunAhead(run, runLen);
-
- if (runLen > 0)
- {
- if (runLen == fReader->GetByteLength() - fReader->GetPosition())
- {
- // the last run in the reader
- fCurrentLine = (FW_Byte*) run;
- fCurrentLineLength = runLen;
- fReader->Advance(fCurrentLineLength);
- fReader = NULL;
- }
- else
- {
- // darn, not the last run -- try to find a newline character
- const FW_Byte* runLimit = run + runLen, *p = run;
-
- while (p < runLimit && *p != FW_PlatformNewLineChar)
- p ++;
-
- if (*p == FW_PlatformNewLineChar)
- {
- // we found a newline
- fCurrentLine = (FW_Byte*) run;
- fCurrentLineLength = p - run + 1;
- fReader->Advance(fCurrentLineLength);
- }
- else
- {
- // no newline, consume the current run...
- ResetBuffer(runLen);
- FW_CMemoryManager::CopyMemory(run, fCurrentLine, runLen);
- fCurrentLineLength = runLen;
- fReader->Advance(fCurrentLineLength);
-
- // ...and keep reading
- FW_Char c;
- while ((c = fReader->GetCharacterAndAdvance()) != 0)
- {
- AppendCharacterToBuffer(c);
- if (c == FW_PlatformNewLineChar)
- break;
- }
-
- if (c == 0)
- fReader = NULL;
- }
- }
-
- }
- else
- fReader = NULL;
-
- #if 0
- ResetBuffer();
-
- FW_Char c;
- while((c = fReader->GetCharacterAndAdvance()) != 0)
- {
- AppendCharacterToBuffer(c);
- if(c == '\n')
- break;
- }
-
- if(c == 0)
- fReader = NULL;
- #endif
- }
- else
- fIsDone = TRUE;
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetCurrentLine
- //----------------------------------------------------------------------------------------
-
- const FW_Byte* FW_CPrivTextBuffer::GetCurrentLine() const
- {
- return fCurrentLine;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::GetCurrentLineLength
- //----------------------------------------------------------------------------------------
-
- FW_ByteCount FW_CPrivTextBuffer::GetCurrentLineLength() const
- {
- return fCurrentLineLength;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::ResetBuffer
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::ResetBuffer(FW_ByteCount size)
- {
- FW_ASSERT(size != 0);
-
- if(gStaticBufferUseCount == 1 && size <= FW_kStaticBufferSize)
- {
- // the static buffer is not in use yet, use it
- fDynamicBufferBase = NULL;
- fCurrentLine = gStaticBuffer;
- fCurrentBufferSize = FW_kStaticBufferSize;
- }
- else
- {
- // the static buffer is in use, allocate a dynamic buffer
- fDynamicBufferSize = size;
- fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::AllocateBlock(fDynamicBufferSize);
- fCurrentLine = fDynamicBufferBase;
- fCurrentBufferSize = fDynamicBufferSize;
- }
-
- fCurrentLineLength = 0;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivTextBuffer::AppendCharacterToBuffer
- //----------------------------------------------------------------------------------------
-
- void FW_CPrivTextBuffer::AppendCharacterToBuffer(FW_Char c)
- {
- if(fCurrentLineLength < fCurrentBufferSize)
- {
- // the buffer is still large enough, just stick the character in
- fCurrentLine[fCurrentLineLength] = c;
- }
- else
- {
- // the buffer ran small
- if(fDynamicBufferBase == NULL)
- {
- // we are switching from a static to a dynamic buffer
- fDynamicBufferSize = 2 * FW_kDynamicBufferSizeIncrement;
- fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::AllocateBlock(fDynamicBufferSize);
- fCurrentLine = fDynamicBufferBase;
- fCurrentBufferSize = fDynamicBufferSize;
-
- // copy the current contents into the dynamic buffer
- ::FW_PrimitiveCopyMemory((const void*)gStaticBuffer, (void*)fDynamicBufferBase, FW_kStaticBufferSize);
- }
- else
- {
- // just reallocate the dynamic buffer
- fDynamicBufferSize += FW_kDynamicBufferSizeIncrement;
- fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::ResizeBlock((void*)fDynamicBufferBase, fDynamicBufferSize);
- fCurrentBufferSize = fDynamicBufferSize;
- }
- }
-
- fCurrentLineLength ++;
- }
-
- //========================================================================================
- // Global Method PrivGetStringSegment
- //========================================================================================
- //
- // Used by word-wrapping text measurement and drawing methods
- //
- // str - the string we're wrapping
- // len - length of the string
- // segStart - start of the segment that should be drawn
- // segLen - length of the segement that should be drawn
- // maxWidth - max width that the string can be when drawn
- // actualWidth - the actual width of the string
- // wordWrap - should we try to wrap text or just draw it in one piece
- // wordBreak - if the first word doesn't fit, should we break it?
-
- FW_Boolean PrivGetStringSegment(ODPlatformCanvas platformCanvas,
- const char* str,
- FW_ByteCount len,
- FW_BytePosition& segStart,
- FW_ByteCount& segLen,
- FW_PlatformCoordinate maxWidth,
- FW_PlatformCoordinate& actualWidth,
- FW_Boolean wordWrap,
- FW_Boolean wordBreak)
- {
- enum
- {
- kSpace = ' ',
- #ifdef FW_BUILD_WIN
- kCR = '\r',
- #endif
- kLF = '\n'
- };
-
- segStart = 0;
- segLen = 0;
-
- // if we encountered an end-line during the previous call, "str" will point to a newline char
- #ifdef FW_BUILD_WIN
- if (*str == kCR && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
- #endif
- if (*str == kLF && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
-
- // skip the leading spaces
- while (*str == kSpace && len > 0)
- {
- str++;
- segStart++;
- len--;
- }
-
- if (len == 0)
- return FALSE;
-
- #ifdef FW_BUILD_WIN
- SIZE size;
- #endif
-
- if (!wordWrap)
- {
- // return the whole string in one chunk
- segLen = len;
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, len, &size);
- actualWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- actualWidth = ::TextWidth(Ptr(str), 0, len);
- #endif
- }
- else
- {
- // break the string into chunks
- FW_PlatformCoordinate accumWidth = 0;
- FW_PlatformCoordinate newWidth;
- FW_PlatformCoordinate wordWidth;
- const char* s = str;
- const char* wordEnd = NULL;
-
- segLen = 0;
-
- while (len > 0)
- {
- // check if we are at the end of a word
- if (*s == kSpace)
- {
- if (*(s - 1) != kSpace)
- {
- wordEnd = s;
- wordWidth = accumWidth;
- }
- }
-
- // check if we have a line terminator
- #ifdef FW_BUILD_WIN
- if (*s == kCR || *s == kLF)
- #endif
- #ifdef FW_BUILD_MAC
- if (*s == kLF)
- #endif
- {
- wordEnd = s;
- wordWidth = accumWidth;
- break;
- }
-
- // add the current char width
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
- newWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- newWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
- #endif
- if (newWidth > maxWidth)
- break;
-
- accumWidth = newWidth;
-
- // advance to the next character
- s++;
- len--;
- }
-
- // the whole string fit just fine
- if (len == 0)
- {
- wordEnd = s;
- wordWidth = accumWidth;
- }
-
- // the first character was too wide
- if (s == str)
- {
- // ... but it was the first character, so draw it anyways!
- s++;
- len--;
- #ifdef FW_BUILD_WIN
- ::GetTextExtentPoint(platformCanvas, str, 1, &size);
- newWidth = size.cx;
- #endif
-
- #ifdef FW_BUILD_MAC
- newWidth = ::TextWidth(Ptr(str), 0, 1);
- #endif
- }
-
- // the first word didn't fit...
- if (wordEnd == NULL)
- {
- if (!wordBreak)
- {
- // it's not ok to break the first word, keep looking
- while (len > 0 && *s != ' ')
- {
- #ifdef FW_BUILD_WIN
- SIZE size;
- ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
- accumWidth = size.cx;
- #endif
- #ifdef FW_BUILD_MAC
- accumWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
- #endif
- s++;
- len--;
- }
- }
-
- wordWidth = accumWidth;
- wordEnd = s;
- }
-
- segLen = wordEnd - str;
- actualWidth = wordWidth;
- }
-
- return TRUE;
- }
-